//---------------[CSE420]----------[Project #4]----------[Part #3]---------------
#include <stdio.h>
#include <string.h>
#include <spu_mfcio.h>
#include "common.h"


//------------------------------[Global Variables]-------------------------------
int blockA_InSPE[BLOCK_SIZE_SQUARED]     QWORD_ALIGNED;
int blockB_InSPE[BLOCK_SIZE_SQUARED]     QWORD_ALIGNED;
int blockC_InSPE[BLOCK_SIZE_SQUARED]     QWORD_ALIGNED;

const int dt_unit = 4096;
CONTROL_BLOCK cb QWORD_ALIGNED;

//----------------------------[Forward Declarations]-----------------------------
void readControlBlock(uint64_t *argp);
void readMatrixBlock(int *spuptr, int *ppuptr);

//------------------------------------[Main]-------------------------------------
int main(uint64_t speid, uint64_t argp, uint64_t envp)
{
	/* Read input data */
	readControlBlock(&argp);

	readMatrixBlock(&blockA_InSPE[0], cb.blockA);
   printf("A data\n");
   for (int i = 0; i < BLOCK_SIZE; ++i)
      for (int k = 0; k < BLOCK_SIZE; ++k)
         printf("%d\n", blockA_InSPE[i * BLOCK_SIZE + k]);

	readMatrixBlock(&blockB_InSPE[0], cb.blockB);
   printf("B data\n");
   for (int j = 0; j < BLOCK_SIZE; ++j)
      for (int k = 0; k < BLOCK_SIZE; ++k)
         printf("%d\n", blockB_InSPE[k * BLOCK_SIZE + j]);

	readMatrixBlock(&blockC_InSPE[0], cb.SPU_result);

	// Multiply just the blocks
   for (int i = 0; i < BLOCK_SIZE; ++i)
      for (int j = 0; j < BLOCK_SIZE; ++j)
         for (int k = 0; k < BLOCK_SIZE; ++k)
         {
            blockC_InSPE[i * BLOCK_SIZE + j] += (blockA_InSPE[i * BLOCK_SIZE + k] * blockB_InSPE[k * BLOCK_SIZE + j]);
            printf("%d\n", blockC_InSPE[i * BLOCK_SIZE + k]);
         }

	/* Write output data */
	mfc_put(&blockC_InSPE, cb.SPU_result, sizeof(int) * BLOCK_SIZE_SQUARED, 2, 0, 0);
	mfc_write_tag_mask(1 << 2);
	mfc_read_tag_status_all();
   printf("end of spu func\n");
}


//---------------------------------[Functions]-----------------------------------
/* Reads control block data from PPE */
void readControlBlock(uint64_t *argp)
{
	mfc_get(&cb, *argp, sizeof(cb), 0, 0, 0);
	mfc_write_tag_mask(1 << 0);
	mfc_read_tag_status_all();
}

/* Reads data block from PPE */
void readMatrixBlock(int *spuptr, int *ppuptr)
{
   printf("START readMatrixBlock\n");
   
	int *spulast = spuptr + BLOCK_SIZE_SQUARED;
	while ( spuptr < spulast )
	{
		int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;
		mfc_get(spuptr, ppuptr, 4 * nwords, 0, 0, 0);
		mfc_write_tag_mask(1 << 0);
		mfc_read_tag_status_all();
		spuptr += dt_unit;
		ppuptr += dt_unit;
	}
   
   printf("END readMatrixBlock\n");
}

//------------------------------------[END]--------------------------------------
